package com.kang.c0c.tree;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Vector;

import com.kang.c0c.optimize.Address;
import com.kang.c0c.optimize.Reg;
import com.kang.c0c.symbol.FunctionSymbol;
import com.kang.c0c.symbol.GlobalTable;
import com.kang.c0c.symbol.NameTable;
import com.kang.c0c.symbol.Symbol;
import com.kang.c0c.tree.node.BinaryNode;
import com.kang.c0c.tree.node.BlockNode;
import com.kang.c0c.tree.node.FunctionNode;
import com.kang.c0c.tree.node.LeafNode;
import com.kang.c0c.tree.node.Node;
import com.kang.c0c.tree.node.Nodes;
import com.kang.c0c.tree.node.SimpleBlock;
import com.kang.c0c.util.Context;

public class TreeTranslator {
	private Tree tree;
	private GlobalTable globalTable;
	private PrintWriter out;
	private int labelNo;	
	private int esp;
	Vector<Reg> pushRegSet;
	
	public TreeTranslator(Context context, String fileName){
		tree = Tree.instance(context);
		globalTable = GlobalTable.instance(context);
		labelNo = -1;
		pushRegSet = null;
		
		out = null;
		try{
			File file = new File("src/com/kang/c0c/out/" + fileName);
			
			if(file.exists() && !file.isDirectory()){
				out = new PrintWriter(file);
			}else if(! file.exists()){
				if(!file.createNewFile())
					System.err.println("Cann't create the new file " + file.getAbsolutePath());
				else
					out = new PrintWriter(file);
			}else{
				System.err.println("The output file is a directory!");
			}
		}catch(IOException ex){
			ex.printStackTrace();
		}
		
		if(out == null)
			out = new PrintWriter(out);
	}
	
	public void translateTree(Context context){
		init();
		initStack();
		initData();
		writeStart();		
		
		int i = 0;
		int treeSize = tree.size();
		
		while(i < treeSize){
			FunctionNode func = tree.getByName(tree.getFunctionName(i));
			showFunction(func);
			
			i++;
		}
		
		writeEnd();
		out.close();
	}
	
	private void init(){
		out.println(";ASM Code>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
		emptyLine();
		
	
		out.println(".386");
		out.println(".MODEL FLAT,STDCALL");
		out.println("option casemap:none");
		out.println("include /masm32/include/io32.inc");
		emptyLine();
	}
	
	private void initStack(){
		out.println(".stack 4096");
		emptyLine();
	}
	
	private void initData(){
		NameTable names = globalTable.nameTable;
		int index = 0, len = names.getVarCount();
		
		out.println(".data");
		
		while(index < len){
			String key = names.getKey(index);
			Symbol sym = names.get(key);
			sym.setName("_" + sym.getName());
			out.println("\t" + sym.getName() + "\tDWORD\t?");
			index ++;
		}
		
		index = 0;
		len = globalTable.listSize();
		while(index < len){
			out.println("\t@str" + index + "\tBYTE\t" + convert(globalTable.getString(index)));
			index ++;
		}
		
		emptyLine();
	}
	
	private void writeStart(){
		out.println(".code");
		out.println("START:");
		out.println("\tCALL\t_main");
		out.println("\tRET");
		emptyLine();
	}
	
	private void emptyLine(){
		out.println();
	}
	
	private void writeEnd(){
		out.println("END\tSTART");
	}
	
	private void ret(){
		emptyLine();
		if(esp < 0)
			binaryOpr("ADD","ESP",""+(-esp));
		
		unaryOpr("POP","EBP");
		out.println("\tRET");
	}
	
	private void initFuncVars(NameTable names){
		int index = 0, size = names.size();
		
		while(index < size){
			Symbol sym = names.get(names.getKey(index));
			if(Symbol.isVar(sym)){
				if(sym.getPos() == 0){
					sym.addr = new Address();
					esp -= 4;
					sym.addr.setStack(esp);
				}
			}
			index++;
		}
	}
	
	private void initFuncBinarys(BlockNode block){		
		int index = 0;
		int size = block.size();
		while(index < size){
			SimpleBlock simple = (SimpleBlock)block.get(index);
			int i = 0, len = simple.binarySize();
			while(i < len){
				BinaryNode binary = simple.getBinary(i);
				binary.addr = new Address();
				i++;
				
				if(binary.getUse() == 1){
					if(i < len){
						BinaryNode next = simple.getBinary(i);
						if(next.getNode() != Nodes.DIV){
							if(binary == next.getLeft())
								continue;
							if(binary == next.getRight())
								continue;
						}
					}else
						continue;
				}
				
				esp -= 4;
				binary.addr.setStack(esp);
			}
			index ++;
		}
				
	}
	
	private void showFunction(FunctionNode function){
		out.println(";Function " + function.getSym().getName() + " Declaration--------");
		out.println("_" + function.getSym().getName() + "\tPROC");
		unaryOpr("PUSH","EBP");
		binaryOpr("MOV","EBP","ESP");
		
		esp = 0;
		initFuncVars(function.getSym().nameTable);
		initFuncBinarys(function.getBlock());
		
		if(esp < 0)
			binaryOpr("SUB","ESP",""+(-esp));
		
		emptyLine();
		
		if(function.getBlock().size() > 0)
			showSimpleBlock((SimpleBlock)function.getBlock().get(0));
				
		if(FunctionSymbol.isVoid(function.getSym())){
			ret();
		}
		
		out.println("_" + function.getSym().getName() + "\tENDP");
		emptyLine();
	}
	
	private void showSimpleBlock(SimpleBlock simple){
		if(simple == null)
			return;
		
		int i = 0, length = simple.binarySize();
		
		if(simple.getBinary(0).getNode() == Nodes.WHILE)
			genWhileCode(simple);
		else{
			while(i < length){
				BinaryNode binary = simple.getBinary(i);
				switch(binary.getNode()){
				//算术运算符
				case Nodes.PLU:
					swap(binary);
					genPlusMinusMulCode("ADD",binary,binary.getLeft(),binary.getRight());
					break;
				case Nodes.SUB:
					genPlusMinusMulCode("SUB",binary,binary.getLeft(),binary.getRight());
					break;
				case Nodes.MUL:
					swap(binary);
					genPlusMinusMulCode("IMUL",binary,binary.getLeft(),binary.getRight());
					break;
				case Nodes.DIV:
					genDivCode(binary,binary.getLeft(),binary.getRight());
					break;
					
				//赋值
				case Nodes.EVA:
					genEVACode((LeafNode)binary.getLeft(),binary.getRight());
					break;
				
				//函数调用及其参数列表
				case Nodes.PARAM:
					i = genParamCode(i,simple);
					i--;
					break;
				case Nodes.CALL:
					genCallCode(binary);
					break;
				
				//系统函数
				case Nodes.RETURN:
					genReturnCode(binary.getLeft());
					break;					
				case Nodes.SCAN:
					genScanCode((LeafNode)binary.getLeft());
					break;
				case Nodes.PRINT:
					genPrintCode((LeafNode)binary.getLeft(),binary.getRight());
					break;
					
				//控制流
				case Nodes.IF:
					genIfCode(binary);					
					break;
				default:
					break;				
				}
				
				i ++;
			}
		}
		if(simple.next != null)
			showSimpleBlock(simple.next);
	}
		
	private void binaryOpr(String opr, String dest, String src){
		out.println("\t" + opr + "\t" + dest + "," + src);
	}
	
	private void unaryOpr(String opr, String arg){
		out.println("\t" + opr + "\t" + arg);
	}
	
	private Reg genPlusMinusMulCode(String op, Node res,Node left, Node right){
		Reg result = stayReg(left);
		Reg opn = stayReg(right);
		
		disposeReg(left);
		if(result != null){
			if(result.getId() < 4){
				Reg reg = getFreeReg(res);
				binaryOpr("MOV",reg.getReg(),result.getReg());
				result = reg;
			}
			
			if(left.getUse() > 0){
				storeNode(left);
				result.remove(left);
			}
			
			if(opn != null)
				binaryOpr(op, result.getReg(), opn.getReg());
			else
				binaryOpr(op, result.getReg(), getStackAddr(right));
			
			result.add(res);
		}else{
			if(opn != null){
				result = genPlusMinusMulCode(op, res, right, left);
				if(op.equalsIgnoreCase("SUB"))
					unaryOpr("NEG",result.getReg());
			}else{
				result = getFreeReg(res);
				binaryOpr("MOV",result.getReg(),getStackAddr(left));
				binaryOpr(op,result.getReg(),getStackAddr(right));
				result.add(res);
			}
		}
		disposeReg(right);
		return result;
	}

	private void genDivCode(Node res, Node left, Node right){
		Reg opn = stayReg(right);
		
		if((opn != null)&&(opn.getId() == 4)){
			clearReg(5);
			binaryOpr("MOV","ECX","EAX");
			clearReg(4);
			opn = Reg.regs[5];
		}
		
		disposeReg(left);
		Reg result = stayReg(left);
		if((result == null)||(result.getId() != 4)){
			clearReg(4);
			if(result == null)
				binaryOpr("MOV","EAX",getStackAddr(left));
			else
				binaryOpr("MOV","EAX",result.getReg());				
			
		}else{
			if(left.getUse() > 0){
				storeNode(left);
				result.remove(left);
			}
		}
		
		clearReg(6);
		binaryOpr("MOV","EDX","0");
		if((opn == null)){
			clearReg(5);
			binaryOpr("MOV","ECX",getStackAddr(right));
			unaryOpr("DIV","ECX");
		}else{
			unaryOpr("DIV",opn.getReg());
		}
		
		Reg.regs[4].add(res);	
		disposeReg(right);
	}
	
	private void genEVACode(LeafNode leaf,Node expr){
		Reg reg = stayReg(expr);
		Reg result = stayReg(leaf);
		
		if(reg != null){
			if((result != null)&&(result.getId() < 4)){
				binaryOpr("MOV",result.getReg(),reg.getReg());
			}else{
				if(reg.getId() < 4){
					if(result == null)
						result = getFreeReg(leaf);
						
					binaryOpr("MOV",result.getReg(),reg.getReg());
				}else{
					if(result != null)
						result.remove(leaf);
					result = reg;
				}
			}
		}else{
			if(result == null)
				result = getFreeReg(leaf);
			
			binaryOpr("MOV",result.getReg(),getStackAddr(expr));
		}
		
		result.add(leaf);
		disposeReg(expr);
		if(leaf.getUse() == 0){
			Symbol sym = (Symbol)leaf.getValue();
			switch(sym.getPos()){
			case 1:
			case 2:
			case 3:
				return;
			default:break;
			}
			
			Address addr = sym.addr;
			if((addr != null)
					&&(addr.getReg() > 0)){
				reg = Reg.regs[addr.getReg()];
				
				if((sym.getPos() == -1)
						||(sym.getUse() > 0))
					storeNode(sym);
				reg.remove(sym);
			}
		}
	}
	
	private void initPushRegSet(){
		pushRegSet = new Vector<Reg>();
		
		int index = 1, size = 7;
		while(index < size){
			Reg reg = Reg.regs[index];
			if(reg.size() > 0){
				pushRegSet.add(reg);
				reg = new Reg(reg.getReg(),reg.getId());
				Reg.regs[index] = reg;
			}
			index++;
		}
		
		index = 0;
		size = pushRegSet.size();
		
		while(index < size){
			unaryOpr("PUSH",pushRegSet.elementAt(index).getReg());
			index ++;
		}
	}
	
	private void restorePushRegs(){
		if(pushRegSet == null)
			return;
		
		int index = pushRegSet.size()-1;
		while(index >= 0){
			Reg reg = pushRegSet.elementAt(index);
			Reg.regs[reg.getId()] = reg;
			unaryOpr("POP",reg.getReg());
			index --;
		}
		pushRegSet = null;
	}
	
	private int paramCodes(int index, 
			SimpleBlock simple, Vector<String> codes){
		BinaryNode binary = simple.getBinary(index);
		Reg reg = stayReg(binary.getLeft());
		String code;
		
		if((reg != null)&&(reg.getId() == 4)){
			code = new String("\tPUSH\t" + reg.getReg());
			codes.add(code);
			disposeReg(binary.getLeft());
			index++;
			binary = simple.getBinary(index);
		}
		clearReg(4);
		
		while(binary.getNode() == Nodes.PARAM){
			reg = stayReg(binary.getLeft());
			if(reg == null){
				code = new String("\tMOV\tEAX," + getStackAddr(binary.getLeft()));
				codes.add(code);
				code = new String("\tPUSH\tEAX");
				codes.add(code);
			}else{
				code = new String("\tPUSH\t" + reg.getReg());
				codes.add(code);
			}
			
			disposeReg(binary.getLeft());
			index++;
			binary = simple.getBinary(index);
		}
		
		return index;
	}
	
	private int genParamCode(int index,SimpleBlock simple){
		Vector<String> codes = new Vector<String>();
		
		index = paramCodes(index,simple,codes);
		initPushRegSet();
		
		while(codes.size() > 0){
			String code = codes.elementAt(0);
			out.println(code);
			codes.remove(0);
		}
		
		return index;
	}
	
	private void genCallCode(BinaryNode binary){
		LeafNode leaf = (LeafNode)binary.getLeft();
		FunctionSymbol sym = (FunctionSymbol)leaf.getValue();
		
		disposeReg(binary);
		if(pushRegSet == null){
			clearReg(4);
			initPushRegSet();
		}
		
		unaryOpr("CALL", "_" + sym.getName());
		if(FunctionSymbol.isInt(sym)){
			Reg.regs[4].add(binary);
		}
		
		if(sym.getParamCount() > 0){
			binaryOpr("ADD","ESP","" + (4*sym.getParamCount()));
		}
		
		restorePushRegs();		
	}
	
	private void genScanCode(LeafNode leaf){
		Symbol sym = (Symbol)leaf.getValue();
		boolean pushEAX;
		
		if(sym.addr == null)
			sym.addr = new Address();
		
		Reg reg = stayReg(leaf);
		if(reg != null){
			if((reg.getId() == 4)||(Reg.regs[4].size() == 0)){
				pushEAX = false;
			}else
				pushEAX = true;
			
			if(pushEAX)
				unaryOpr("PUSH","EAX");
			
			unaryOpr("ReadSDecDword",reg.getReg());
			
			if(pushEAX)
				unaryOpr("POP","EAX");
			sym.addr.setStored(false);
		}else{
			String stack = getStackAddr(leaf);
			if(stack == null){
				Reg free = getFreeReg(leaf);
				if((free.getId() == 4)||(Reg.regs[4].size() == 0)){
					pushEAX = false;
				}else
					pushEAX = true;
				
				if(pushEAX)
					unaryOpr("PUSH","EAX");

				unaryOpr("ReadSDecDword",free.getReg());
				
				if(pushEAX)
					unaryOpr("POP","EAX");
				free.add(leaf);
			}else{
				if(Reg.regs[4].size() == 0){
					pushEAX = false;
				}else
					pushEAX = true;
				
				if(pushEAX)
					unaryOpr("PUSH","EAX");
				
				unaryOpr("ReadSDecDword",stack);
				
				if(pushEAX)
					unaryOpr("POP","EAX");
				sym.addr.setStored(true);
			}
		}
		
		disposeReg(leaf);
	}
	
	private void genPrintCode(LeafNode leaf, Node node){
		if(leaf != null){
			int index = (Integer)leaf.getValue();
			unaryOpr("WriteString","@str" + index);
			disposeReg(leaf);
		}
		
		if(node != null){
			Reg reg = stayReg(node);
			if(reg != null){
				unaryOpr("WriteSDecDword",reg.getReg());
			}else{
				String stack = getStackAddr(node);
				if(stack != null)
					unaryOpr("WriteSDecDword",stack);
				else
					unaryOpr("WriteSDecDword","0");
			}
			disposeReg(node);
		}
	}
	
	private void genReturnCode(Node node){
		if(node != null){
			Reg reg = stayReg(node);
			if(reg == null){
				binaryOpr("MOV","EAX",getStackAddr(node));
			}else if(reg.getId() != 4)
				binaryOpr("MOV","EAX",reg.getReg());
			
			disposeReg(node);
		}
		ret();
	}
	
	private void genIfCode(BinaryNode binary){
		Node cond = binary.getLeft();
		String label1 = getLabel();
		printIfRelation(cond,label1);
		
		BinaryNode node = (BinaryNode)binary.getRight();
		showSimpleBlock((SimpleBlock)node.getRight());
		String label2 = getLabel();
		unaryOpr("JMP",label2);
		
		out.println(label1 + ":");
		showSimpleBlock((SimpleBlock)node.getLeft());
		out.println(label2 + ":");
	}
	
	private void genWhileCode(SimpleBlock simple){
		String start = getLabel();
		String end = getLabel();
		out.println(start + ":");
		
		BinaryNode loop = simple.getBinary(0);
		BinaryNode cond = simple.getBinary(simple.binarySize()-1);
		simple.removeLast();		
		simple.removeFirst();
		
		if(simple.binarySize() > 0)
			showLoopBlock(simple);
		
		printWhileRelation(cond,end);
		
		SimpleBlock execBlock = (SimpleBlock)loop.getRight();
		showSimpleBlock(execBlock);
		unaryOpr("JMP",start);
		out.println(end + ":");
	}
	
	private void showLoopBlock(SimpleBlock simple){
		if(simple == null)
			return;
		
		int i = 0, length = simple.binarySize();		
		while(i < length){
			BinaryNode binary = simple.getBinary(i);
			switch(binary.getNode()){
			//算术运算符
			case Nodes.PLU:
				swap(binary);
				genPlusMinusMulCode("ADD",binary,binary.getLeft(),binary.getRight());
				break;
			case Nodes.SUB:
				genPlusMinusMulCode("SUB",binary,binary.getLeft(),binary.getRight());
				break;
			case Nodes.MUL:
				swap(binary);
				genPlusMinusMulCode("IMUL",binary,binary.getLeft(),binary.getRight());
				break;
			case Nodes.DIV:
				genDivCode(binary,binary.getLeft(),binary.getRight());
				break;
			default:
				break;				
			}			
			i ++;
		}
	}
	
	private void genCmpCode(Node left, Node right){
		Reg leftReg = stayReg(left);
		Reg rightReg = stayReg(right);
		
		if(leftReg == null){
			leftReg = getFreeReg(left);
			binaryOpr("MOV",leftReg.getReg(),getStackAddr(left));
			leftReg.add(left,true);
		}
		
		if(rightReg != null){
			binaryOpr("CMP", leftReg.getReg(), rightReg.getReg());
		}else
			binaryOpr("CMP", leftReg.getReg(), getStackAddr(right));
		
		disposeReg(left);
		disposeReg(right);
	}
	
	private void printIfRelation(Node cond, String label){
		if(cond == null)
			return;
		if(cond instanceof LeafNode)
			return;
		
		BinaryNode condB = (BinaryNode)cond;
		genCmpCode(condB.getLeft(),condB.getRight());
		
		switch(cond.getNode()){
		case Nodes.EQU:
			unaryOpr("JE",label);
			break;
		case Nodes.NEQ:
			unaryOpr("JNE",label);
			break;
		case Nodes.GT:
			unaryOpr("JG",label);
			break;
		case Nodes.GEQ:
			unaryOpr("JGE",label);
			break;
		case Nodes.LT:
			unaryOpr("JL",label);
			break;
		case Nodes.LEQ:
			unaryOpr("JLE",label);
			break;
		default:
			break;
		}
	}
	
	private void printWhileRelation(Node cond, String label){		
		if(cond == null)
			return;
		if(cond instanceof LeafNode)
			return;
		
		BinaryNode condB = (BinaryNode)cond;
		genCmpCode(condB.getLeft(),condB.getRight());
		
		switch(cond.getNode()){
		case Nodes.EQU:
			unaryOpr("JNE",label);
			break;
		case Nodes.NEQ:
			unaryOpr("JE",label);
			break;
		case Nodes.GT:
			unaryOpr("JNG",label);
			break;
		case Nodes.GEQ:
			unaryOpr("JL",label);
			break;
		case Nodes.LT:
			unaryOpr("JNL",label);
			break;
		case Nodes.LEQ:
			unaryOpr("JG",label);
			break;
		default:
			break;
		}
	}

	/**
	 * 得到当前节点在堆栈中的地址
	 * 如果节点存储的是一个数字是则返回其值
	 * 当当前节点没有被分配到堆栈地址时并返回NULL
	 * 
	 * @param node
	 * @return	返回值为null时表示当前节点未被分配到地址
	 */
	private String getStackAddr(Object node){
		if(node instanceof Symbol){
			return getStackAddr((Symbol)node);
		}else if(node instanceof LeafNode){
			LeafNode leaf = (LeafNode)node;
			switch(leaf.getNode()){
			case Nodes.NUM:
				return "" + leaf.getValue();
			case Nodes.VAR:
				return getStackAddr((Symbol)leaf.getValue());
			default:
				return null;
			}
		}else if(node instanceof BinaryNode){
			Address addr = ((BinaryNode)node).addr;
			if(addr == null)
				return null;
			else{
				int pos = addr.getStack();
				if(pos > 0)
					return "[EBP+" + pos + "]";
				else
					return "[EBP-" + (-pos) + "]";
			}				
		}
		return null;
	}
	
	/**
	 * 得到当前变量在堆栈中的地址
	 * 当当前变量没有被分配到堆栈地址时并返回NULL
	 * 
	 * @param sym
	 * @return	返回值为null时表示当前节点未被分配到地址
	 */
	private String getStackAddr(Symbol sym){
		if(sym.getPos() == -1)//全局变量
			return sym.getName();
		
		if((sym.addr == null)||
				(sym.addr.getStack() == -1))
			return null;
		
		int pos = sym.addr.getStack();
		if(pos > 0)
			return "[EBP+" + pos + "]";
		else
			return "[EBP-" + (-pos) + "]";
	}
	
	/**
	 * 得到当前节点所在的寄存器中
	 * 
	 * @param node
	 * @return	返回值是NULL表示此节点暂时未分配到寄存器
	 */
	private Reg stayReg(Node node){
		Address addr = null;
		
		if(node instanceof LeafNode){
			if(node.getNode() == Nodes.VAR){
				Symbol sym = (Symbol)((LeafNode)node).getValue();
				addr = sym.addr;
			}
		}else if(node instanceof BinaryNode){
			addr = ((BinaryNode)node).addr;
		}
		
		if(addr == null)
			return null;
		else if(addr.getReg() <= 0)
			return null;
		return Reg.regs[addr.getReg()];
	}
	
	/**
	 * 为当前节点请求一个空寄存器
	 * 如果所有寄存器已满，则清空一个值在内存中有存储的寄存器，并返回此寄存器
	 * 如果所有寄存器已满而且所有寄存器的值都未被存储在内存中，则清空EAX,并返回
	 * 
	 * 注：清空寄存器指把寄存器的描述符清空，如果寄存器中的值未配存储，清空前需要作存储操作
	 * 
	 * @return
	 */
	private Reg getFreeReg(Node node){
		Reg reg = getGlobalReg(node);
		if(reg != null)
			return reg;
		
		int index = 4;
		while(index < 7){
			if(Reg.regs[index].size() == 0)
				return Reg.regs[index];
			index ++;
		}
		
		reg = storedReg();
		if(reg != null)
			return reg;
		
		return clearReg(4);
	}
	
	/**
	 * 判断当前节点是否是被分配了全局寄存器的节点
	 * 如果是，则返回它被分配的寄存器
	 * 否则，返回NULL
	 * 
	 * @param node
	 * @return
	 */
	private Reg getGlobalReg(Node node){
		if(node == null)
			return null;
		
		if(node instanceof LeafNode){
			if(node.getNode() != Nodes.VAR)
				return null;
			
			Symbol sym = (Symbol)((LeafNode)node).getValue();
			if((sym.getPos() >= 1)&&
					(sym.getPos() <=3))
				return Reg.regs[sym.getPos()];
		}
		return null;
	}
	
	/**
	 * 得到一个所有值已在堆栈或data段内存中有存储的寄存器
	 * 
	 * @return	返回NULL表示不存在这样的寄存器
	 */
	private Reg storedReg(){
		int index = 4;
		while(index < 6){
			Iterator<Object> nodes = Reg.regs[index].iterator();
			boolean stored = true;
			
			while(nodes.hasNext()){
				Object node = nodes.next();
				Address addr = null;
				if(node instanceof Symbol){
					addr = ((Symbol)node).addr;	
				}else if(node instanceof BinaryNode){
					addr = ((BinaryNode)node).addr;
				}
				
				if(addr != null)
					if(! addr.isStored()){
						stored = false;
						break;
					}
			}
			
			if(stored)
				return Reg.regs[index];
			
			index ++;
		}
		
		return null;
	}
	
	/**
	 * 清空寄存器Reg.regs[index]，以获得一个空寄存器以供使用
	 * 
	 * @return
	 */
	private Reg clearReg(int index){
		Iterator<Object> nodes = Reg.regs[index].iterator();
		while(nodes.hasNext()){
			Object node = nodes.next();
			storeNode(node);
		}
			
		Reg.regs[index].clear();
		return Reg.regs[index];
	}
	
	/**
	 * 如果检查发现当前节点在后续中将不再被使用，则释放它所占用的寄存器
	 * 内存中堆栈存储由于线性增长的原因，所以暂时无法释放，只有在函数结束处统一处理
	 * 
	 * @param node
	 */
	private void disposeReg(Node node){
		node.decUse();
		
		if(node.getUse() > 0)
			return;
		
		if(node instanceof LeafNode){
			LeafNode leaf = (LeafNode)node;
			if(leaf.getNode() == Nodes.VAR){
				Symbol sym = (Symbol)leaf.getValue();
				switch(sym.getPos()){
				case 1:
				case 2:
				case 3:
					return;
				default:break;
				}
				
				Address addr = sym.addr;
				if((addr != null)
						&&(addr.getReg() > 0)){
					Reg reg = Reg.regs[addr.getReg()];
					
					if((sym.getPos() == -1)
							||(sym.getUse() > 0))
						storeNode(sym);
					reg.remove(sym);
				}
			}
		}else if(node instanceof BinaryNode){
			Address addr = ((BinaryNode)node).addr;
			if((addr != null)&&(addr.getReg() > 0)){
				Reg reg = Reg.regs[addr.getReg()];
				reg.remove((BinaryNode)node);
			}
		}
	}
	
	/**
	 * 当当前节点所在的寄存器需要被清空、而当前节点的值又需要被使用时，将此节点保存到其相应的内存中
	 * 如果是全局变量，则保存至它的data段内
	 * 如果不是，则保存进它所在的堆栈地址中
	 * 
	 * @param node
	 */
	private void storeNode(Object node){
		Address addr = null;
		Object dest = null;
		
		if(node instanceof Symbol){
			dest = node;
			addr = ((Symbol)node).addr;
		}else if(node instanceof LeafNode){
			LeafNode leaf = (LeafNode)node;
			if(leaf.getNode() == Nodes.VAR){
				Symbol sym = (Symbol)leaf.getValue();
				addr = sym.addr;
				dest = sym;				
			}
		}else if(node instanceof BinaryNode){
			addr = ((BinaryNode)node).addr;
			dest = node;
		}
		
		if(addr.getReg() < 4)
			return;
		if(! addr.isStored()){
			binaryOpr("MOV",getStackAddr(dest),Reg.regs[addr.getReg()].getReg());
			addr.setStored(true);
		}
	}
	
	/**
	 * 获取标签，用于在if和while等控制流语句中作跳转标志
	 * @return
	 */
	private String getLabel(){
		labelNo ++;
		return "@Label" + labelNo;
	}
	
	private boolean isNumber(Node node){
		return node.getNode() == Nodes.NUM;
	}
	/**
	 * 交换二叉节点的左右节点，使得数值会在第二个操作数的位置上
	 * 
	 * @param left
	 * @param right
	 */
	private void swap(BinaryNode binary){
		if(! isNumber(binary.getLeft()))
			return;
		Node temp = binary.getLeft();
		binary.setLeft(binary.getRight());
		binary.setRight(temp);
	}
	
	/**
	 * 转换需要输出的字符串，主要是处理字符串中的转义字符到ASCII码的转化
	 * 
	 * @param param
	 * @return
	 */
	private String convert(String param){
		String code = "";
		int i = 0;
		
		while(i < param.length()){
			char ch = param.charAt(i);
			
			if(ch == '\\'){
				i ++;
				ch = param.charAt(i);
				
				switch(ch){
				case 'b':
					code += "08h,";
					break;
				case 't':
					code += "09h,";
					break;
				case 'n':
					code += "0dh,0ah,";
					break;
				case 'f':
					code += "0ch,";
					break;
				case 'r':
					code += "0dh,";
					break;
				case '"':
					code += "'\"',";
					break;
				case '\'':
					code +=  "'\'',";
					break;
				case '\\':
					code += "'\\',";
					break;
				default:
					code += "'" + ch + "',";
					break;
				}
			}else{
				code += "'" + ch + "',";
			}
			
			i ++;
		}
		
		code += "0";
		
		return code;
	}
}
